package pdf2img.utils;

import lombok.Data;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.jpedal.PdfDecoder;
import org.jpedal.exception.PdfException;
import org.jpedal.fonts.FontMappings;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.Optional;

/**
 * @program: cmp-service
 * @create: 2021-10-18 10:51
 **/
@Data
public class PdfUtils {


    //经过测试,dpi为96,100,105,120,150,200中,105显示效果较为清晰,体积稳定,dpi越高图片体积越大,一般电脑显示分辨率为96
    public static final float DEFAULT_DPI = 144;
    //默认转换的图片格式为jpg
    public static final String DEFAULT_FORMAT = "jpg";

    private int width = 0;
    private int height = 0;
    private byte[] file = null;


    /**
     * 高内存, 清晰    使用pdfbox
     *
     * @param file
     * @return
     * @throws IOException
     */
    public static PdfUtils pdfToJpgImgByPdfbox(byte[] file) throws IOException {
        PDDocument pdDocument = PDDocument.load(file);
        PDFRenderer renderer = new PDFRenderer(pdDocument);
        List<BufferedImage> resultList = new LinkedList<>();
        //循环每个页码
        for (int i = 0; i < pdDocument.getNumberOfPages(); i++) {
            BufferedImage image = renderer.renderImageWithDPI(i, DEFAULT_DPI, ImageType.RGB);
            resultList.add(image);
        }
        pdDocument.close();
        return mergeListImage2PdfUtils(resultList);
    }

    /**
     * 低内存, 转出来模糊 使用jpedal-lgpl 和下面两个仓库
     *
     * @param file
     * @return
     * @throws PdfException
     * @throws IOException
     */
    public static PdfUtils pdfToJpgImgByjpedal(byte[] file) throws PdfException, IOException {
        PdfDecoder decode_pdf = new PdfDecoder(true);
        FontMappings.setFontReplacements();
        ByteArrayInputStream inputStream = new ByteArrayInputStream(file);
        decode_pdf.openPdfFileFromInputStream(inputStream, false);
        int pageCount = decode_pdf.getPageCount();
        List<BufferedImage> resultList = new LinkedList<>();
        for (int i = 1; i <= pageCount; i++) {
            BufferedImage img = decode_pdf.getPageAsImage(i);
            resultList.add(img);
        }
        inputStream.close();
        decode_pdf.closePdfFile();
        return mergeListImage2PdfUtils(resultList);
    }

    private static PdfUtils mergeListImage2PdfUtils(List<BufferedImage> resultList) throws IOException {
        PdfUtils result = new PdfUtils();
        if (CollectionUtils.isNotEmpty(resultList)) {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            BufferedImage bufferedImage = mergeListImage(resultList);
            result.setWidth(bufferedImage.getWidth());
            result.setHeight(bufferedImage.getHeight());
            ImageIO.write(bufferedImage, DEFAULT_FORMAT, outputStream);
            byte[] bytes = outputStream.toByteArray();
            outputStream.close();
            result.setFile(bytes);
        }
        return result;
    }

    private static BufferedImage mergeListImage(List<BufferedImage> resultList) {
        int width = resultList.get(0).getWidth();
        Optional<Integer> max = resultList.stream()
                .map(BufferedImage::getWidth)
                .distinct()
                .max(Comparator.comparingInt(a -> a));
        if (max.isPresent()) {
            width = max.get();
        }
        Integer reduce = resultList.stream()
                .map(BufferedImage::getHeight)
                .reduce(0, Integer::sum);
        BufferedImage imageResult = new BufferedImage(width, reduce, BufferedImage.TYPE_INT_RGB);
        Graphics2D graphics = imageResult.createGraphics();
        int height = 0;
        for (BufferedImage bufferedImage : resultList) {
            graphics.drawImage(bufferedImage, 0, height, width, bufferedImage.getHeight(), null);
            height += bufferedImage.getHeight();
        }
        graphics.dispose();
        return imageResult;
    }

    public static void main(String[] args) throws IOException, PdfException {
        byte[] bytes = FileUtils.readFileToByteArray(new File("D:\\window\\桌面\\商品房买卖合同.pdf"));
        PdfUtils pdfUtils = pdfToJpgImgByjpedal(bytes);
//        PdfUtils pdfUtils = pdfToJpgImg(bytes);
        FileUtils.writeByteArrayToFile(new File("D:\\window\\桌面\\图片.png"), pdfUtils.getFile());
    }

    private PdfUtils() {
    }
}
